package org.hcyspartnoc.demo.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.hcyspartnoc.demo.common.core.PageBean;
import org.hcyspartnoc.demo.common.core.enums.CoreSysRole;
import org.hcyspartnoc.demo.common.enums.system.SysRoleStatusEnum;
import org.hcyspartnoc.demo.common.exception.system.SysRoleException;
import org.hcyspartnoc.demo.mapper.system.SysRoleMapper;
import org.hcyspartnoc.demo.mapper.system.SysRolePermissionMapper;
import org.hcyspartnoc.demo.mapper.system.SysRoleUserMapper;
import org.hcyspartnoc.demo.pojo.dto.system.SysRoleAddDto;
import org.hcyspartnoc.demo.pojo.dto.system.SysRoleModifyDto;
import org.hcyspartnoc.demo.pojo.dto.system.SysRoleQueryPageDto;
import org.hcyspartnoc.demo.pojo.dto.system.SysRoleUpdateDto;
import org.hcyspartnoc.demo.pojo.po.system.SysRolePermissionPo;
import org.hcyspartnoc.demo.pojo.po.system.SysRolePo;
import org.hcyspartnoc.demo.pojo.po.system.SysRoleUserPo;
import org.hcyspartnoc.demo.pojo.vo.system.SysRoleVo;
import org.hcyspartnoc.demo.pojo.vo.system.SysRoleVoPermissionsVo;
import org.hcyspartnoc.demo.service.system.ISysRoleService;
import org.hcyspartnoc.demo.utils.StringUtils;
import org.hcyspartnoc.demo.utils.redis.RedisComponent;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRolePo> implements ISysRoleService {
    private static final ArrayList<CoreSysRole> ALL_CORE_ROLE = new ArrayList<>();

    static {
        Collections.addAll(ALL_CORE_ROLE, CoreSysRole.values());
    }

    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private SysRolePermissionMapper sysRolePermissionMapper;
    @Resource
    private RedisComponent redisComponent;

    @Override
    @Transactional
    public SysRoleVo addRole(SysRoleAddDto sysRoleAddDto) throws SysRoleException {
        // 校验该角色名称是否已经存在
        roleExistsThrow(sysRoleAddDto.getName());
        // 插入角色
        SysRolePo sysRolePo = BeanUtil.copyProperties(sysRoleAddDto, SysRolePo.class);
        save(sysRolePo);
        return rolePoToVo(sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, sysRolePo.getId())));
    }

    @Override
    @Transactional
    public SysRoleVo modifyRole(SysRoleModifyDto sysRoleModifyDto) throws SysRoleException {
        // 检查被修改的是否是禁止操作的角色
        if (ALL_CORE_ROLE.contains(CoreSysRole.getById(sysRoleModifyDto.getId())))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 检查id是否存在
        roleNotExistsThrow(sysRoleModifyDto.getId());
        // 检查新名称是否重复
        SysRolePo savedRolePo = sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getName, sysRoleModifyDto.getName()));
        // 如果新昵称已经被别的角色占用
        if (Objects.nonNull(savedRolePo))
            if (!Objects.equals(savedRolePo.getId(), sysRoleModifyDto.getId()))
                throw new SysRoleException(SysRoleException.ROLE_HAS_EXISTS);
        // 修改角色信息
        SysRolePo sysRolePo = BeanUtil.copyProperties(sysRoleModifyDto, SysRolePo.class);
        saveOrUpdate(sysRolePo);
        return rolePoToVo(sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, sysRolePo.getId())));
    }

    @Override
    @Transactional
    public void removeRole(Integer roleId) throws SysRoleException {
        // 角色为核心角色异常
        if (ALL_CORE_ROLE.contains(CoreSysRole.getById(roleId)))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_REMOVE);
        // 角色不存在异常
        roleNotExistsThrow(roleId);
        // 换绑用户角色为普通角色
        sysRoleUserMapper.update(new LambdaUpdateWrapper<>(SysRoleUserPo.class)
                .eq(SysRoleUserPo::getRoleId, roleId)
                .set(SysRoleUserPo::getRoleId, CoreSysRole.NORMAL_USER.getId()));
        // 删除角色
        removeById(roleId);
    }

    @Override
    public PageBean<SysRolePo, SysRoleVo> queryByPage(SysRoleQueryPageDto sysRoleQueryPageDto) {
        int current=sysRoleQueryPageDto.getCurrent();
        int pageSize=sysRoleQueryPageDto.getPageSize();
        String roleName=sysRoleQueryPageDto.getName();
        String roleDesc=sysRoleQueryPageDto.getDescription();
        String startTime=sysRoleQueryPageDto.getStartTime();
        String endTime=sysRoleQueryPageDto.getEndTime();
        String sortField=sysRoleQueryPageDto.getSortField();
        String sortOrder=sysRoleQueryPageDto.getSortOrder();
        LambdaQueryWrapper<SysRolePo> wrapper = new LambdaQueryWrapper<>(SysRolePo.class);
        // 根据角色名称进行模糊查询
        if (Objects.nonNull(roleName) && !roleName.isEmpty()) {
            wrapper.like(SysRolePo::getName, roleName);
        }
        // 根据角色描述进行模糊查询
        if (Objects.nonNull(roleDesc) && !roleDesc.isEmpty()) {
            wrapper.like(SysRolePo::getDescription, roleDesc);
        }
        // 根据开始时间和结束时间进行范围查询
        if (Objects.nonNull(startTime) && !startTime.isEmpty() && Objects.nonNull(endTime) && !endTime.isEmpty()) {
            wrapper.between(SysRolePo::getCreateTime, startTime, endTime);
        }
        // 根据排序字段和排序顺序进行排序
        if (Objects.nonNull(sortField) && !sortField.isEmpty() && Objects.nonNull(sortOrder) && !sortOrder.isEmpty()) {
            if ("asc".equalsIgnoreCase(sortOrder)) {
                wrapper.orderByAsc(getSortColumn(sortField));
            } else if ("desc".equalsIgnoreCase(sortOrder)) {
                wrapper.orderByDesc(getSortColumn(sortField));
            }
        }
        //---------------------------------------------------------------------
        Page<SysRolePo> page = new Page<>(current, pageSize);
        Page<SysRolePo> sysRolePoPage = sysRoleMapper.selectPage(page, wrapper);
        ArrayList<SysRoleVo> sysRoleVos = new ArrayList<>();
        for (SysRolePo sysRolePo : sysRolePoPage.getRecords()) {
            sysRoleVos.add(rolePoToVo(sysRolePo));
        }
        for (SysRoleVo sysRoleVo:sysRoleVos){
            Integer id = sysRoleVo.getId();
            //获取权限id
            List<Integer> selectperid = sysRoleMapper.selectperid(id);
            ArrayList<SysRoleVoPermissionsVo> permissions=new ArrayList<>();
            for (Integer perid:selectperid){
                SysRoleVoPermissionsVo sysRoleVoPermissionsVo=new SysRoleVoPermissionsVo();
                sysRoleVoPermissionsVo.setId(perid);
                sysRoleVoPermissionsVo.setPermissionName(sysRoleMapper.selectpername(perid,id));
                permissions.add(sysRoleVoPermissionsVo);
            }
            //获取所有权限名字
            sysRoleVo.setPermissionNamesl(sysRoleMapper.selectallperName());
            sysRoleVo.setPermissions(permissions);
        }
        return new PageBean<>(page, sysRoleVos);
    }
    // 根据排序字段名称获取对应的 Lambda 表达式
    private SFunction<SysRolePo, ?> getSortColumn(String sortField) {
        switch (sortField) {
            case "roleName":
                return SysRolePo::getName;
            case "roleDesc":
                return SysRolePo::getDescription;
            case "createTime":
                return SysRolePo::getCreateTime;
            // 可以根据实际情况添加更多的排序字段
            default:
                return SysRolePo::getId;
        }
    }

    @Override
    @Transactional
    public void modifyStatus(Integer roleId) throws SysRoleException {
        // 超级管理员不允许修改
        if (CoreSysRole.SUPER_ADMIN.getId().equals(roleId))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 角色不存在异常
        SysRolePo sysRolePo = roleNotExistsThrow(roleId);
        // 修改状态
        SysRoleStatusEnum newStatus = SysRoleStatusEnum.USABLE;
        if (Objects.requireNonNull(SysRoleStatusEnum.getByCode(sysRolePo.getStatus())).equals(SysRoleStatusEnum.USABLE))
            newStatus = SysRoleStatusEnum.DISABLE;
        sysRoleMapper.update(new LambdaUpdateWrapper<>(SysRolePo.class)
                .set(SysRolePo::getStatus, newStatus.getCode())
                .eq(SysRolePo::getId, roleId));
        // 修改redis状态
        redisComponent.setRole(roleId, newStatus.getCode());
    }

    @Override
    public SysRoleVo addRolebyper(SysRoleAddDto sysRoleAddDto) {
        SysRolePo sysRolePo=new SysRolePo();
        BeanUtils.copyProperties(sysRoleAddDto,sysRolePo);
        sysRolePo.setCreateTime(LocalDateTime.now());
        sysRolePo.setStatus(1);
        List<Integer> permissionIds = sysRoleAddDto.getPermissionIds();
        sysRoleMapper.insert(sysRolePo);
        Integer roleid=sysRoleMapper.selectroleid(sysRoleAddDto.getName());
        SysRolePermissionPo sysRolePermissionPo=new SysRolePermissionPo();
        for(Integer permission:permissionIds){
                sysRolePermissionMapper.insertinto(roleid,permission);
        }
        return null;
    }

    @Override
    @Transactional
    public void sysRoleUpdate(SysRoleUpdateDto sysRoleUpdate) {
        //修改角色基本信心
        SysRolePo sysRolePo=new SysRolePo();
        BeanUtils.copyProperties(sysRoleUpdate,sysRolePo);
        sysRoleMapper.updateById(sysRolePo);
        //修改角色的权限信息
        //1.将角色的权限全部删除
        Integer roleid = sysRolePo.getId();
        sysRoleMapper.deleteperbyid(roleid);
        //2.将角色新的权限加上
        List<Integer> permissionIds = sysRoleUpdate.getPermissionIds();
        for (Integer permission:permissionIds){
            sysRoleMapper.insertidperandrole(permission,roleid);
        }
    }

    @Override
    public void removerolebyid(Integer role) {
        removeById(role);
       sysRoleMapper.deleteperbyid(role);
    }


    private SysRoleVo rolePoToVo(SysRolePo sysRolePo) {
        SysRoleVo sysRoleVo = BeanUtil.copyProperties(sysRolePo, SysRoleVo.class);
        sysRoleVo.setFormatCreateTime(StringUtils.formatDateTime(sysRolePo.getCreateTime()));

        return sysRoleVo;
    }

    private void roleExistsThrow(String name) throws SysRoleException {
        if (sysRoleMapper.exists(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getName, name)))
            throw new SysRoleException(SysRoleException.ROLE_HAS_EXISTS);
    }

    private SysRolePo roleNotExistsThrow(Integer roleId) throws SysRoleException {
        SysRolePo sysRolePo = sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, roleId));
        if (Objects.isNull(sysRolePo))
            throw new SysRoleException(SysRoleException.ROLE_NOT_EXISTS);
        return sysRolePo;
    }

}
